// Copyright (c) 2012 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "net/dns/host_resolver.h"

#include "base/logging.h"
#include "base/metrics/field_trial.h"
#include "base/strings/string_number_conversions.h"
#include "base/strings/string_split.h"
#include "base/values.h"
#include "net/base/net_errors.h"
#include "net/dns/dns_client.h"
#include "net/dns/dns_config_service.h"
#include "net/dns/host_cache.h"
#include "net/dns/host_resolver_impl.h"

namespace net {

namespace {

    // Maximum of 6 concurrent resolver threads (excluding retries).
    // Some routers (or resolvers) appear to start to provide host-not-found if
    // too many simultaneous resolutions are pending.  This number needs to be
    // further optimized, but 8 is what FF currently does. We found some routers
    // that limit this to 6, so we're temporarily holding it at that level.
    const size_t kDefaultMaxProcTasks = 6u;

} // namespace

PrioritizedDispatcher::Limits HostResolver::Options::GetDispatcherLimits()
    const
{
    PrioritizedDispatcher::Limits limits(NUM_PRIORITIES, max_concurrent_resolves);

    // If not using default, do not use the field trial.
    if (limits.total_jobs != HostResolver::kDefaultParallelism)
        return limits;

    // Default, without trial is no reserved slots.
    limits.total_jobs = kDefaultMaxProcTasks;

    // Parallelism is determined by the field trial.
    std::string group = base::FieldTrialList::FindFullName(
        "HostResolverDispatch");

    if (group.empty())
        return limits;

    // The format of the group name is a list of non-negative integers separated
    // by ':'. Each of the elements in the list corresponds to an element in
    // |reserved_slots|, except the last one which is the |total_jobs|.
    std::vector<base::StringPiece> group_parts = base::SplitStringPiece(
        group, ":", base::TRIM_WHITESPACE, base::SPLIT_WANT_ALL);
    if (group_parts.size() != NUM_PRIORITIES + 1) {
        NOTREACHED();
        return limits;
    }

    std::vector<size_t> parsed(group_parts.size());
    size_t total_reserved_slots = 0;

    for (size_t i = 0; i < group_parts.size(); ++i) {
        if (!base::StringToSizeT(group_parts[i], &parsed[i])) {
            NOTREACHED();
            return limits;
        }
    }

    size_t total_jobs = parsed.back();
    parsed.pop_back();
    for (size_t i = 0; i < parsed.size(); ++i) {
        total_reserved_slots += parsed[i];
    }

    // There must be some unreserved slots available for the all priorities.
    if (total_reserved_slots > total_jobs || (total_reserved_slots == total_jobs && parsed[MINIMUM_PRIORITY] == 0)) {
        NOTREACHED();
        return limits;
    }

    limits.total_jobs = total_jobs;
    limits.reserved_slots = parsed;
    return limits;
}

HostResolver::Options::Options()
    : max_concurrent_resolves(kDefaultParallelism)
    , max_retry_attempts(kDefaultRetryAttempts)
    , enable_caching(true)
{
}

HostResolver::RequestInfo::RequestInfo(const HostPortPair& host_port_pair)
    : host_port_pair_(host_port_pair)
    , address_family_(ADDRESS_FAMILY_UNSPECIFIED)
    , host_resolver_flags_(0)
    , allow_cached_response_(true)
    , is_speculative_(false)
    , is_my_ip_address_(false)
{
}

HostResolver::~HostResolver()
{
}

void HostResolver::SetDnsClientEnabled(bool enabled)
{
}

void HostResolver::ChangeRequestPriority(RequestHandle req,
    RequestPriority priority)
{
    NOTIMPLEMENTED();
}

HostCache* HostResolver::GetHostCache()
{
    return nullptr;
}

std::unique_ptr<base::Value> HostResolver::GetDnsConfigAsValue() const
{
    return nullptr;
}

// static
std::unique_ptr<HostResolver> HostResolver::CreateSystemResolver(
    const Options& options,
    NetLog* net_log)
{
    return std::unique_ptr<HostResolver>(new HostResolverImpl(options, net_log));
}

// static
std::unique_ptr<HostResolver> HostResolver::CreateDefaultResolver(
    NetLog* net_log)
{
    return std::unique_ptr<HostResolver>(
        new HostResolverImpl(Options(), net_log));
}

HostResolver::HostResolver()
{
}

} // namespace net
